﻿#ifndef CODEC_NBIOT_H
#define CODEC_NBIOT_H

#include <qobject.h>
#include "ObjAutoInject.h"
#include <qbytearray.h>
#include <qlist.h>
#include <qhash.h>
#include <qtimer.h>
#include "SerialPortManager.h"

class NBIOTInstruction;

class LogSaver;
class Codec_NBIoT : public QObject,public ObjAutoInject
{
  Q_OBJECT
private:
  const char LF='\n';
  const char CR='\r';
  const QByteArray OK="OK";
  const QByteArray COMMA=",";
  const QByteArray EQUAL="=";
  const QByteArray ERROR="ERROR";
  const QByteArray MIPLCONFIG="+MIPLCONFIG";
  const QByteArray MIPLDISCOVER="+MIPLDISCOVER";
  const QByteArray MIPLEVENT="+MIPLEVENT";
  const QByteArray MIPLWRITE="+MIPLWRITE";
  const QByteArray MIPLCREATE="AT+MIPLCREATE";
  const QByteArray MIPLDELETE="AT+MIPLDELETE";
  const QByteArray MIPLADDOBJ="AT+MIPLADDOBJ";
  const QByteArray MIPLDELOBJ="AT+MIPLDELOBJ";
  const QByteArray MIPLOPEN="AT+MIPLOPEN";
  const QByteArray MIPLCLOSE="AT+MIPLCLOSE";
  const QByteArray MIPLDISCOVERRSP="AT+MIPLDISCOVERRSP";
  const QByteArray MIPLWRITERSP="AT+MIPLWRITERSP";
  const QByteArray MIPLNOTIFY="AT+MIPLNOTIFY";
  const QByteArray CEREG="AT+CEREG?";//查询连接状态
  const QByteArray NSOCR="AT+NSOCR";//创建socket
  const QByteArray NSOST="AT+NSOST";//发送消息
  const QByteArray NSORF="AT+NSORF";//接收消息
  const QByteArray NSOCL="AT+NSOCL";//删除socket

  const QByteArray NSONMI="+NSONMI";//有消息需要接收
  const QByteArray CEREG_feedBack="+CEREG";//检查连接注册状态的反馈

private://property
  QByteArray dataBuffer;//串口数据缓冲区
  QList<NBIOTInstruction*> instructionQueue;//指令发送队列
  void(Codec_NBIoT::*handleNohead)(int)=Q_NULLPTR;//无头部数据处理函数的指针
  void(Codec_NBIoT::*handleError)()=Q_NULLPTR;//错误处理函数的指针
  NBIOTInstruction* lastNBIOTInstruction=Q_NULLPTR;//上一条发送的NB指令
  NBIOTInstruction* readDataInstruction=Q_NULLPTR;//读取数据时要发送的指令
  bool RSP=true;
  bool baseStationConnection=false;
  int currentIndex=0;
  QHash<QByteArray,void(Codec_NBIoT::*)(int)> decodeFunctionMap;

private://dependency
  SerialPortManager* serialPortManager = Q_NULLPTR;
  LogSaver* logSaver = Q_NULLPTR;
public:
  explicit Codec_NBIoT();
  virtual ~Codec_NBIoT();
public slots:
  void slot_decode(QByteArray newData);//接收串口数据并添加到数据缓冲区

signals:
  void signal_MIPLCONFIG(QString mode,QString arg1,QString arg2);
  void signal_MIPLDISCOVER(QString ref,QString msgId,QString objId);
  void signal_MIPLEVENT(QString ref,QString evtId);
  void signal_MIPLWRITE(QString ref,QString msgId,QString objId,QString insId,QString resId,QString valueType,QString len ,QString value,QString flag,QString index);

  void signal_baseStationConnected();
  void signal_newSocketId(QString socketID);
  void signal_newSocketMsg(QString socketID,QString senderHost,ushort senderPort,int len,QByteArray data);

public:
  bool isRSP();
  bool isBaseStationConnected();
public://ONENECT
  void AT_MIPLCREATE();//创建实例
  void AT_MIPLDELETE(QString ref);//删除实例
  void AT_MIPLADDOBJ(QString ref,QString objId,QString insCount,QString insBitmap,QString attrCount,QString actCount);//创建对象
  void AT_MIPLDELOBJ(QString ref,QString objId);//删除对象
  void AT_MIPLOPEN(QString ref,QString lifeTime,QString timeOut);//打开连接
  void AT_MIPLCLOSE(QString ref);//关闭连接
  void AT_MIPLDISCOVERRSP(QString ref ,QString msgId,QString result,QString valueString);//回应资源发现指令
  void AT_MIPLWRITERSP(QString ref,QString msgId,QString result);//回应写命令
  void AT_MIPLNOTIFY(QString ref,QString msgId,QString objId,QString insId,QString resId,QString valueType,QString value);//主动发送资源值
public://TCP/IP
  void AT_CEREG();
  void AT_NSOCR(QString port);
  void AT_NSOST(QString socketID,QString targetHostAddress,QString targetPort,QByteArray data);
  void AT_NSORF(QString socketID,QString len);
  void AT_NSOCL(QString socketID);
private:
  void decode();//数据解析
  void sendData(NBIOTInstruction* nBIOTInstruction);
  void sendDataImmediately(NBIOTInstruction* nBIOTInstruction);
  void sendData1();

  void decode_OK();
  void decode_ERROR();

  void decode_MIPLCONFIG(int lengthOfInstruction);//解析OneNet配置
  void decode_MIPLDISCOVER(int lengthOfInstruction);//解析OneNet资源发现
  void decode_MIPLEVENT(int lengthOfInstruction);//解析OneNet连接事件
  void decode_MIPLWRITE(int lengthOfInstruction);//解析OneNet写命令

  void decode_NSONMI(int lengthOfInstruction);//有新的消息需要读
  void decode_CEREG(int lengthOfInstruction);

  void decode_noHead(int lengthOfInstruction);
  void decode_noHead_CREATESOCKET(int lengthOfInstruction);
  void decode_noHead_SENDUDPDATA(int lengthOfInstruction);
  void decode_noHead_READSOCKET(int lengthOfInstruction);

  void handleError_AT_NSOST();
public:
  void dataBufferDropData(int len);//数据缓冲区丢弃数据
  QByteArray dataBufferGetData(int len);//从数据缓冲区得到数据
  QStringList getArgList(int len,int begin);
  bool isEqual(const char * charPtr1,const char * charPtr2,int len);
  int findColon(const char * charPtr,int len);
public:
  SerialPortManager* getSerialPortManager();
  void setSerialPortManager(SerialPortManager* serialPortManager);
public:
  virtual void objectAutoInjection(QHash<QString,QObject*>* objMap)override;
};
class NBIOTInstruction
{
  friend class Codec_NBIoT;
private://property
  QByteArray* instruction=Q_NULLPTR;
  void(Codec_NBIoT::*handle)(int)=Q_NULLPTR;
  void(Codec_NBIoT::*handleError)()=Q_NULLPTR;
  void(Codec_NBIoT::*handleOk)()=Q_NULLPTR;
  NBIOTInstruction(QByteArray* instruction,
                   void(Codec_NBIoT::*handle)(int)=Q_NULLPTR,
                   void(Codec_NBIoT::*handleError)()=Q_NULLPTR,
                   void(Codec_NBIoT::*handleOk)()=Q_NULLPTR)
  {
    this->instruction=instruction;
    this->handle=handle;
    this->handleError=handleError;
    this->handleOk=handleOk;
  }
  ~NBIOTInstruction()
  {
    delete instruction;
  }
  QByteArray* getInstruction()
  {
    return instruction;
  }

};
#endif // CODEC_NBIOT_H
